package nconv.convert;

import nconv.utils.LogCenter;
import nconv.wiki.MediaWikiProxy;
import org.apache.poi.hwpf.HWPFDocumentCore;
import org.apache.poi.hwpf.converter.AbstractWordUtils;
import org.apache.poi.hwpf.usermodel.Table;
import org.apache.poi.hwpf.usermodel.TableCell;
import org.apache.poi.hwpf.usermodel.TableRow;
import org.w3c.dom.*;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ConvertUtils {

	public static final boolean processImage = true;
	public static final boolean skipProcessImageIfTargetExists = true;
	public static final boolean uploadImage = true;
	public static final boolean uploadDocWikiPage = true;
	public static final boolean uploadAVPWikiPage = true;
	public static final boolean uploadDiameterCommandPage = true;

	public static String getSameCharStr(char ch, int cnt) {
		if (cnt <= 0) return "";
		
		char[] chs = new char[cnt];
		Arrays.fill(chs, ch);
		return new String(chs);
	}
	
	public static int[] buildTableCellEdgesArray(Table table) {
		Set<Integer> edges = new TreeSet<Integer>();

		for (int r = 0; r < table.numRows(); r++) {
			TableRow tableRow = table.getRow(r);
			for (int c = 0; c < tableRow.numCells(); c++) {
				TableCell tableCell = tableRow.getCell(c);

				edges.add(tableCell.getLeftEdge());
				edges.add(tableCell.getLeftEdge() + tableCell.getWidth());
			}
		}

		Integer[] sorted = edges.toArray(new Integer[edges.size()]);
		int[] result = new int[sorted.length];
		for (int i = 0; i < sorted.length; i++) {
			result[i] = sorted[i];
		}

		return result;
	}

	public static String processRetStr(String srcFileName, BaseWordConverter converter) throws Exception {
		File srcFile = new File("input/" + srcFileName);
		
		final HWPFDocumentCore wordDocument = AbstractWordUtils.loadDoc(srcFile);
		converter.processDocument(wordDocument);
		
		DOMSource domSource = new DOMSource(converter.getDocument());
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		StreamResult streamResult = new StreamResult(baos);

		TransformerFactory tf = TransformerFactory.newInstance();
		Transformer serializer = tf.newTransformer();
		serializer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
		serializer.setOutputProperty(OutputKeys.INDENT, "no");
		serializer.setOutputProperty(OutputKeys.METHOD, "text");
		serializer.transform(domSource, streamResult);
		return new String(baos.toByteArray(), "UTF-8");
	}

	public static void processTGPPDoc(String srcFileName) throws Exception {
		TGPPRefProcessor.reloadRefs(false);
		String fileNameNoExt = srcFileName.substring(0, srcFileName.indexOf('.'));
		String specName = fileNameNoExt;
		int dashIdx = fileNameNoExt.indexOf('-');
		if (dashIdx > 0) {
			specName = fileNameNoExt.substring(0, dashIdx);
		}
		ConvertUtils.process(srcFileName, new TGPP2WikiConverter(specName), null, specName);

		updateMainPage();
	}

	static Pattern specInfoPattern = Pattern.compile("\\|-\\n+" +
			"\\|([^\\|]+)\\n+" + //spec name
			"\\|([^\\|]+)\\n+" + //spec version
			"\\|([^\\|]+)\\n+" + //spec title
		//	"\\|([^\\|]+)\\n+" + //spec group
			"\\|([^\\|]*)\\n+"  //3gpp link
	);

	static class SpecInfoRow {
		String name;
		String version;
		String title;
	//	String group;
		String link;
	}

	static Map<String, SpecInfoRow> specInfoMap = new TreeMap<>();

	public static void updateMainPage() throws Exception {
		final String mainPageTitle = "Main Page";
		final String specStartMark = "<!-- spec start-->";
		final String specEndMark = "<!-- spec end-->";
		MediaWikiProxy proxy = MediaWikiProxy.getWikiSite(MediaWikiProxy.WikiSite.AUTO_WIKI);
		String content = proxy.getPageContent(mainPageTitle);
		int start = content.indexOf(specStartMark);
		int end = content.indexOf(specEndMark);
		if (start > 0 && end > 0 && end > start) {
			String table = content.substring(start + specStartMark.length(), end);
			int row1Idx = table.indexOf("|-");
			if (row1Idx < 0) { //no page

			} else {
				Matcher m = specInfoPattern.matcher(table);
				while (m.find()) {
					SpecInfoRow row = new SpecInfoRow();
					row.name = m.group(1);
					row.version = m.group(2);
					row.title = m.group(3);
				//	row.group = m.group(4);
					row.link = m.group(4);
					specInfoMap.put(row.name, row);
				}
			}
		} else { //nothing to do
			return;
		}
		String[] titles = ConvertContext.getDocTitle().trim().split("\\n");
		SpecInfoRow row = new SpecInfoRow();
		row.name = "[[" + ConvertContext.getCoreDocName() + "]]";
		row.version = ConvertContext.getDocName().substring(6, 9) + "\n" + titles[titles.length - 1];
		StringBuilder builder = new StringBuilder();
		for (int i = 2; i < titles.length - 1; i++) {
			builder.append(titles[i] + "\n");
		}
		row.title = builder.toString().trim();
		//row.group = titles[1];
		row.link = "[http://www.3gpp.org/DynaReport/" + ConvertContext.getCoreDocName() + ".htm 3GPP Link]";
		specInfoMap.put(row.name, row);

		builder = new StringBuilder();
		builder.append(content.substring(0, start))
				.append(specStartMark)
				.append("\n{|class=\"wikitable collapsible sortable\"")
				.append("\n!Spec Name" +
						"\n!Spec Version" +
						"\n!Spec Title" +
				//		"\n!Group" +
						"\n!3GPP Link");
		for (String spec : specInfoMap.keySet()) {
			SpecInfoRow curr = specInfoMap.get(spec);
			builder.append("\n|-")
					.append("\n|").append(curr.name).append("")
					.append("\n|").append(curr.version).append("")
					.append("\n|").append(curr.title)
			//		.append("\n|").append(curr.group)
					.append("\n|").append(curr.link);

		}
		builder.append("\n|}");
		builder.append("\n").append(content.substring(end));
		proxy.createPage(mainPageTitle, builder.toString(), "Update main page for spec update");

	}

	public static void processFDDoc(String srcFileName) throws Exception {
		String fdName = srcFileName.substring(0, srcFileName.indexOf('.'));
		ConvertContext.setDocName(fdName);
		ConvertUtils.process(srcFileName, new FD2WikiConverter(fdName), null, fdName);
	}

	public static void process(String srcFileName, BaseWordConverter converter) throws Exception {
		process(srcFileName, converter, null, null);
	}

	public static void process(String srcFileName, BaseWordConverter converter, String prefix) throws Exception {
		process(srcFileName, converter, prefix, null);
	}

	private static void process(String srcFileName, BaseWordConverter converter, String prefix, String coreFileName) throws Exception {
		
		String dstFileName = prefix != null && prefix.length() > 0 ? prefix + "-" : "";
		int dotIdx = srcFileName.indexOf('.');
		if (dotIdx >= 0) {
			dstFileName += srcFileName.substring(0, dotIdx) + ".txt";
			if (coreFileName == null) {
				coreFileName = srcFileName.substring(0, dotIdx);
			}
		} else {
			dstFileName += srcFileName;
		}
		
		File dstFile = new File("output/" + (coreFileName == null ? "" : coreFileName + "/") + dstFileName);
		if (!dstFile.getParentFile().exists()) {
			dstFile.getParentFile().mkdir();
		}
		ImageHandler.setOutputDir(dstFile.getParent());
		ImageHandler.setInputDir("input/" + (coreFileName == null ? "" : coreFileName + "/"));
		
		File srcFile = new File("input/" + srcFileName);
		System.out.println("Converting " + srcFile.getAbsolutePath());
		final HWPFDocumentCore wordDocument = AbstractWordUtils.loadDoc(srcFile);
		converter.processDocument(wordDocument);
		
		List<String> pageNameList = new ArrayList<>();
		getPageNames(converter.getDocument(), pageNameList);
		
		if (pageNameList.size() == 0) {
			Document doc = converter.getDocument();
			generateFile(doc,
					new File(dstFile.getParentFile().getAbsolutePath() + File.separator + reviseFileName(coreFileName) + ".txt"));
			if (converter instanceof WikiConverter) {
				uploadImages(doc);
				generateWikiPage(doc, null, coreFileName);
			}
		} else {
			generate3GPPSummaryWikiPage((TGPP2WikiConverter)converter, coreFileName, pageNameList);
			for (String aPage : pageNameList) {
				Document subDoc = getDocumentForPage(converter.getDocument(), aPage);
				generateFile(subDoc,
						new File(dstFile.getParentFile().getAbsolutePath() + File.separator + reviseFileName(aPage) + ".txt"));
				if (converter instanceof WikiConverter) {
					uploadImages(subDoc);
					generateWikiPage(subDoc, coreFileName, aPage);
				}
			}
		}

		if (converter instanceof  WikiConverter)
			((WikiConverter)converter).summary();
	}

	public static final String AMBOX_NO_EDIT = "{{Ambox\n|nocat=true\n| type  = content\n" +
			"| text  = This page is automatically generated by program, don't edit this page as the revisions can be lost.\n}}";

	public static void generate3GPPSummaryWikiPage(TGPP2WikiConverter converter, String docName, List<String> pageNameList) {
		String title = converter.getDocumentHead().getAttribute(TGPP2WikiConverter.ATTR_SPEC_TITLE);
		StringBuilder sb = new StringBuilder(AMBOX_NO_EDIT);
		sb.append("\n\n{{Ambox")
				.append("\n|nocat=true")
				.append("\n| type  = notice")
				.append("\n| text  = This page is generated from 3GPP Spec "
						+ DocUtils.getSpecDocFileName(docName)
						+ ", for latest doc refer to [http://www.3gpp.org/DynaReport/" + docName + ".htm 3GPP TS/TR " + docName + "]")
				.append("\n}}");
		if (title != null && title.length() > 0) {
			sb.append("\n\n'''<pre>" + title + "</pre>'''");
		}
		sb.append("\n\n");
		for (String pageName : pageNameList) {
			sb.append("* [[" + pageName + "]]\n");
		}

		if (converter.definedDiameterCommands.size() > 0) {
			sb.append("\n\n{{CotList16|Title=Diameter Commands|expand=yes");
			for (String command : converter.definedDiameterCommands) {
				sb.append("|" + command);
			}
			sb.append("}}");
		}

		if (converter.definedAVPs.size() > 0) {
			sb.append("\n\n{{CotListMultiCols|Title=Diameter AVPs|Col=4|expand=yes|");
			for (String avpName : converter.definedAVPs) {
				sb.append("\n* [[AVP:" + avpName + "|" + avpName + "]]");
			}
			sb.append("}}");
		}

		if (uploadDocWikiPage) {
			try {
				MediaWikiProxy.getWikiSite(MediaWikiProxy.WikiSite.AUTO_WIKI).createPage(
						docName, sb.toString(), "Initial create");
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	public static List<Node> getChildNodeList(Node element) {
		List<Node> list = new ArrayList<Node>();
		NodeList nl = element.getChildNodes();
		for (int i = 0; i < nl.getLength(); i++) {
			list.add(nl.item(i));
		}
		return list;
	}
	
	private static void uploadImages(Document doc) {
		if (!uploadImage) return;

		List<String> nameList = new ArrayList<>();
		scanImageNames(doc, nameList);
		for (String name : nameList) {
			String fileName = null;
			if (name.startsWith(WikiPicturesManager.MANUAL_PREFIX)){
				fileName = ImageHandler.getInputDir() + name;
				if (!new File(fileName).exists()) {
					continue;
				}
			} else {
				fileName = ImageHandler.getOutputDir() + name;
			}
			try {
				MediaWikiProxy.getWikiSite(MediaWikiProxy.WikiSite.AUTO_WIKI).uploadFile(fileName, name);
			} catch (Exception e) {
				System.err.println("Failed to upload image to wiki: " + name);
			}
		}
	}
	
	public static void scanImageNames(Node node, List<String> nameList) {
		if (node instanceof Text) {
			return;
		} else if (node instanceof Element) {
			Element element = (Element)node;
			if (element.hasAttribute(WikiConverter.IMAGE_NAME)) {
				nameList.add(element.getAttribute(WikiConverter.IMAGE_NAME));
			}
		}
		
		List<Node> childList = getChildNodeList(node);
		for (Node child : childList) {
			scanImageNames(child, nameList);
		}
	}

	private static boolean firstNodeFound = false;
	public static Document getDocumentForPage(Document src, String pageName) throws ParserConfigurationException {
		Document dst = (Document)src.cloneNode(true);

		Node body = getDocumentBody(dst);
		LinkedList<Node> ll = new LinkedList<>(getChildNodeList(body));

		boolean withinRange = false;
		final String travesedMark = "TraversedMark";
		while (ll.size() > 0) {
			Node node = ll.peekFirst();

			if (node instanceof Text || isHeading((Element)node) || ((Element) node).hasAttribute(travesedMark)) {
				ll.pollFirst();
			}

			if (node instanceof Text) {
				if (!withinRange) node.getParentNode().removeChild(node);
			} else {
				Element element = (Element) node;
				if (isHeading(element)) {
					String currPageName = element.getAttribute(WikiConverter.PAGE_NAME);
					if (pageName.equals(currPageName)) {
						withinRange = true;
						if (element.hasAttribute(WikiConverter.MARK_PAGE_CLAUSE) && element.getParentNode() != null) {
							element.getParentNode().removeChild(element);
						}
					} else {
						withinRange = false;
						if (element.getParentNode() != null)
							element.getParentNode().removeChild(element);
					}
					continue;
				}
				if (element.hasAttribute(travesedMark)) {
					if (!withinRange && element.getFirstChild() == null) {
						element.getParentNode().removeChild(element);
					}
				} else {
					element.setAttribute(travesedMark, "true");
					ll.addAll(0, getChildNodeList(element));
				}
			}
		}

/*
			if (node instanceof Text) {
				if (!withinRange) node.getParentNode().removeChild(node);
			} else {
				Element element = (Element)node;
				if (isHeading(element)) {
					String currPageName = element.getAttribute(WikiConverter.PAGE_NAME);
					if (pageName.equals(currPageName)) {
						withinRange = true;
					} else {
						withinRange = false;
						node.getParentNode().removeChild(node);
					}
				} else if (node.getChildNodes().getLength() == 0){
					if (!withinRange)
						node.getParentNode().removeChild(node);
				} else {
					ll.addAll(0, getChildNodeList(node));
				}
			}
		}

		Node node = locateFirstNodeOfPage(dst, pageName);
		if (node != null) {
			removeLeftNodes(node, body, ((Element)node).hasAttribute(WikiConverter.MARK_PAGE_CLAUSE));
		}
		firstNodeFound = false;
		node = locateLastNodeOfPage(dst, pageName);
		if (node != null) {
			removeRightNodes(node, body, true);
		}
		*/
		return dst;
	}	
	
	private static Node getDocumentBody(Document doc) {
		Element docElement = doc.getDocumentElement();
		for (Node child : getChildNodeList(docElement)) {
			if (child.getNodeName().equals("body")) {
				return child;
			}
		}
		return null;
	}

	public static void generateFile(Document doc, File outFile) {
		System.out.println("Saving output to " + outFile.getAbsolutePath());
		DOMSource domSource = new DOMSource(doc);

		FileOutputStream baos = null;
		try {
			baos = new FileOutputStream(outFile);
		} catch (FileNotFoundException e) {
		}
		StreamResult streamResult = new StreamResult(baos);

		try {
			TransformerFactory tf = TransformerFactory.newInstance();
			Transformer serializer = tf.newTransformer();
			serializer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
			serializer.setOutputProperty(OutputKeys.INDENT, "no");
			serializer.setOutputProperty(OutputKeys.METHOD, "text");
			serializer.transform(domSource, streamResult);
		} catch (Exception e) {
			System.err.println("Failed to save output to file: " + outFile.getAbsolutePath());
		}
	}

	public static void generateWikiPage(Document doc, String specName, String pageName) {
		if (!uploadDocWikiPage) return;

		DOMSource domSource = new DOMSource(doc);
		
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		StreamResult streamResult = new StreamResult(baos);

		try {
			TransformerFactory tf = TransformerFactory.newInstance();
			Transformer serializer = tf.newTransformer();
			serializer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
			serializer.setOutputProperty(OutputKeys.INDENT, "no");
			serializer.setOutputProperty(OutputKeys.METHOD, "text");
			serializer.transform(domSource, streamResult);
			System.out.println("Saving page to WIKI: " + pageName);
			StringBuffer header = new StringBuffer(AMBOX_NO_EDIT);
			if (specName != null) {
				header.append("\n\n").append("{{Ambox")
						.append("\n|nocat=true")
						.append("\n| type  = notice")
						.append("\n| text  = Refer to page [[" + specName + "]] for all the pages in current specification")
						.append("\n}}");
			}
			MediaWikiProxy.getWikiSite(MediaWikiProxy.WikiSite.AUTO_WIKI)
					.createPage(pageName, header + "\n<br/>\n" + baos.toString("UTF-8"), "Create page " + pageName);
		} catch (Exception e) {
			System.err.println("Failed to save page to WIKI: " + pageName);
		}
	}

	final static String MISSING_DEFINITION_CONTENT = "'''Missing AVP definition!!!'''";

	public static void uploadAVPPage(String avpName, String definition, TGPP2WikiConverter.AVPInfo info,
									 List<String> parentAVPs, List<String> inMessages) {
		if (!uploadAVPWikiPage) return;
		MediaWikiProxy proxy = MediaWikiProxy.getWikiSite(MediaWikiProxy.WikiSite.AUTO_WIKI);
		/*
		try {
			if (proxy.hasPage(avpName)) return;
		} catch (Exception e) {
			e.printStackTrace();
			return;
		}
		*/
		String prefixPageName = "AVP:" + avpName;
		final String avpParentWiki = "{{AVP parent";
		final String avpInMsgWiki = "{{AVP in";

		if (info == null) {
			LogCenter.logWiki(prefixPageName, LogCenter.DOC_OPERATION.NOTICE, "Missing AVP basic information when creating AVP page.");
			info = new TGPP2WikiConverter.AVPInfo(avpName);
		}
		if (definition == null) {
			LogCenter.logWiki(prefixPageName, LogCenter.DOC_OPERATION.NOTICE, "Missing AVP details when creating AVP page.");
			definition = MISSING_DEFINITION_CONTENT;
		}

		try {
			String currPage = proxy.getPageContent(prefixPageName);
			int existingStartIndex = -1;
			if (currPage != null) {
				if (definition.equals(MISSING_DEFINITION_CONTENT) && !currPage.contains(MISSING_DEFINITION_CONTENT)) {
					LogCenter.logWiki(prefixPageName, LogCenter.DOC_OPERATION.NOTICE, "Replacing AVP definition with NULL");
				}
				existingStartIndex = currPage.indexOf(avpParentWiki);
			}

			String avpInfoWiki = null;

			if (currPage != null && existingStartIndex >= 0) { //has existing parent AVPs info
				avpInfoWiki = currPage.substring(existingStartIndex + avpParentWiki.length(),
						currPage.indexOf("}}", existingStartIndex));
			}

			if (parentAVPs != null && parentAVPs.size() > 0) {
				for (String aParent : parentAVPs) {
					String section = "|" + aParent;
					if (avpInfoWiki != null) {
						if (!avpInfoWiki.contains(section))
							avpInfoWiki += section;
					} else {
						avpInfoWiki = section;
					}
				}
			}

			if (avpInfoWiki != null) {
				definition += avpParentWiki + avpInfoWiki + "}}\n\n";
			}

			//continue to process InMsg template
			existingStartIndex = -1;
			if (currPage != null)
				existingStartIndex = currPage.indexOf(avpInMsgWiki);

			avpInfoWiki = null;

			if (currPage != null && existingStartIndex >= 0) { //has existing parent AVPs info
				avpInfoWiki = currPage.substring(existingStartIndex + avpInMsgWiki.length(),
						currPage.indexOf("}}", existingStartIndex));
			}

			if (inMessages != null && inMessages.size() > 0) {
				for (String aMsg : inMessages) {
					String section = "|" + aMsg;
					if (avpInfoWiki != null) {
						if (!avpInfoWiki.contains(section))
							avpInfoWiki += section;
					} else {
						avpInfoWiki = section;
					}
				}
			}

			if (avpInfoWiki != null) {
				definition += avpInMsgWiki + avpInfoWiki + "}}";
			}

		} catch (Exception e) {
			e.printStackTrace();
		}

		String avpGeneralInfo = "{{Infobox AVP\n" +
				"|name       = " + avpName + "\n" +
				"|code       = " + info.code + "\n" +
				"|valuetype  = " + info.valueType + "\n" +
				"|must       = " + info.must + "\n" +
				"|may        = " + info.may + "\n" +
				"|shouldnot  = " + info.shouldNot + "\n" +
				"|mustnot    = " + info.mustNot + "\n" +
				"|encr       = " + info.mayEncr + "\n" +
				"|definedin  = [[" + info.specName + "]]\n" +
				"}}";
		String pageContent = avpGeneralInfo + "\n\n" + definition;
		try {
			proxy.createPage(prefixPageName, pageContent, "Create/update AVP page");
		} catch (Exception e) {
			e.printStackTrace();
		}
		String noPrefixPage = "#REDIRECT [[AVP:" + avpName + "]]\n\n[[Category:AVP]]";
		try {
			proxy.createPage(avpName, noPrefixPage, "Create/update AVP page");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}



	public static void updateAVPInMessage(String avpName, List<String> inMessages) {
		if (!uploadAVPWikiPage || inMessages == null || inMessages.size() == 0) return;

		MediaWikiProxy proxy = MediaWikiProxy.getWikiSite(MediaWikiProxy.WikiSite.AUTO_WIKI);
		/*
		try {
			if (proxy.hasPage(avpName)) return;
		} catch (Exception e) {
			e.printStackTrace();
			return;
		}
		*/
		String prefixPageName = "AVP:" + avpName;
		final String avpParentWiki = "{{AVP parent";
		final String avpInMsgWiki = "{{AVP in";

		try {
			String currPage = proxy.getPageContent(prefixPageName);
			int existingStartIndex = -1;

			//continue to process InMsg template
			existingStartIndex = -1;
			if (currPage == null) {
				LogCenter.log("Try to update AVP-in-message but the AVP page is not found: " + prefixPageName);
				return;
			}

			existingStartIndex = currPage.indexOf(avpInMsgWiki);

			String avpInfoWiki = null;

			if (existingStartIndex >= 0) { //has existing parent AVPs info
				avpInfoWiki = currPage.substring(existingStartIndex + avpInMsgWiki.length(),
						currPage.indexOf("}}", existingStartIndex));
			} else { //has AVP-parent?

			}

			for (String aMsg : inMessages) {
				String section = "|" + aMsg;
				if (avpInfoWiki != null) {
					if (!avpInfoWiki.contains(section))
						avpInfoWiki += section;
				} else {
					avpInfoWiki = section;
				}
			}

			avpInfoWiki = avpInMsgWiki + avpInfoWiki + "}}";

			if (existingStartIndex >= 0) { //replace
				currPage = currPage.substring(0, existingStartIndex) + avpInfoWiki + currPage.substring(currPage.indexOf("}}", existingStartIndex) + 2);
			} else {
				currPage += avpInfoWiki + "\n\n";
			}

			proxy.createPage(prefixPageName, currPage, "Add AVP-in-message information");

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void createDiameterCommandPage(String page, String ref) {
		if (!uploadDiameterCommandPage) return;
		MediaWikiProxy proxy = MediaWikiProxy.getWikiSite(MediaWikiProxy.WikiSite.AUTO_WIKI);
		String content = "#REDIRECT [[" + ref + "]]\n\n[[Category:Diameter message]]";
		try {
			proxy.createPage(page, content, "Establish diameter diameterCommand quick reference");
		} catch (Exception e) {
			e.printStackTrace();
		}

	}
	
	public static void removeLeftNodes(Node start, Node root, boolean inclusive) {
		if (start == root) return;
		
		Node parent = start.getParentNode();
		List<Node> tobe = new ArrayList<>();
		for (Node child : getChildNodeList(parent)) {
			if (child == start){
				if (inclusive) {
					tobe.add(child);
				}
				break;
			}
			else tobe.add(child);
		}
		for (Node n : tobe) {
			parent.removeChild(n);
		}
		removeLeftNodes(parent, root, false);
	}
	
	public static void getPageNames(Node node, List<String> pageList) {
		if (node instanceof Text) {
			return;
		} else if (node instanceof Element) {
			String pageNameAttr = null;
			if (((Element)node).hasAttribute(WikiConverter.PAGE_NAME)) {
				pageNameAttr = ((Element)node).getAttribute(WikiConverter.PAGE_NAME);
				if (!pageList.contains(pageNameAttr)) {
					pageList.add(pageNameAttr);
				}
			}
		}
		
		List<Node> childList = getChildNodeList(node);
		for (Node child : childList) {
			getPageNames(child, pageList);
		}
	}
	
	public static String reviseFileName(String fileName) {
		String target = fileName.replaceAll("[^a-zA-Z0-9.-]", "_");
		if (!target.equals(fileName)) {
			System.out.println("File named revised, original: " + fileName + ", revised: " + target);
		}
		return target;
	}
	
	public static boolean isHeading(Element element) {
		String styleName = element.getAttribute(WikiConverter.ATTR_STYLE_NAME);
		
		if (styleName != null && styleName.startsWith("Heading")) {
			return true;
		} 
		return false;
	}
}
